前情提要:昨天了解了HOC的概念,但礙於手邊有的東西不好變化,也有可能是手邊的redux,對於一次結合覺得有點複雜,今天就用簡單的react application來實作HOC吧!
首先,我們的情境是...
頁面所需的資料userList透過api取得,每次做非同步處理的時候都需要等待response的時間,我希望user在等待時有loading畫面,而loading這塊使用HOC處理。
備註:這邊的練習沒有使用redux。
這邊建立一個App component透過api取得user資料,然後將userList資料和Loading狀態作為props送給UserList。
這邊為了避免不重要的fetch過程佔版面,所以只顯示部分程式碼。
// ...
return (
<div>
<UserList
isLoading={this.state.isLoading}
userList={this.state.userList} />
</div>
);
// ...
在HOC這邊,還記得昨天提到的概念嗎?HOC就是一個component包著另一個component!(好饒舌啊!!!)
我把UserList component送來後,將props的內容拆成:isLoading和其餘props,
接著判斷props的isLoading狀態是否為true,若為ture顯示isLoading的gif圖片,若為false則顯示渲染被包裹的component(在這邊指UserList)。
如此一來當未來我有其他資料需要loading的時候就可以透過withLoading處理loading顯示。
import React from "react";
const withLoading = WrappedComponent => ({ isLoading, ...props }) => {
return isLoading ? (
<img
src="https://loading.io/spinners/balls/lg.circle-slack-loading-icon.gif"
alt="loading"
/>
) : (
<WrappedComponent {...props} />
);
};
export default withLoading;
而在UserList這邊,我只需要將寫好的withLoading匯入,並將UserList送進withLoading處理,就可以免除等待response期間無資料的空白期。
import React from "react";
import withLoading from "../hoc/with_loading";
const UserList = ({ userList }) => {
return userList.map((user, index) => (
<div key={index}>
<img src={user.picture.thumbnail} alt="" />
<ul style={{display: 'inline-block'}}>
<li>name: {`${user.name.first} ${user.name.last}`}</li>
<li>gender: {user.gender}</li>
<li>email: {user.email}</li>
</ul>
</div>
));
};
export default withLoading(UserList);
測試畫面如下:
完整程式碼請參考:github傳送門
今日總結:
HOC幫助我們把component與component之間類似的行爲抽出使用,覺得最困難的點是判斷哪些邏輯是共通的可以抽出使用,或許它也跟reduxㄧ樣,當我們需要HOC的時候,它自然就會出來向我們招手了。
參考資料:Handle loadings in React by using Higher Order Components